package com.wu.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wu.error.BusinessException;
import com.wu.error.EnumBusinessError;
import com.wu.mapper.*;
import com.wu.pojo.Users;
import com.wu.pojo.model.UserMainModel;
import com.wu.pojo.model.UserToken;
import com.wu.service.UsersService;
import com.wu.util.FTPUtil;
import com.wu.util.MyUtil;
import com.wu.util.RedisUtil;
import com.wu.util.TokenUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

import static com.wu.constant.Constant.*;

/**
 * @author: 吴磊
 * @program: blog
 * @create: 2021-04-19 20:10
 */
@Service
public class UsersServiceImpl extends ServiceImpl<UsersMapper, Users> implements UsersService {
    @Autowired
    private UsersMapper usersMapper;

    @Autowired
    private MyUtil myUtil;

    @Autowired
    private TokenUtils tokenUtils;

    @Autowired
    private UserLevelMapper userLevelMapper;

    @Autowired
    private ArticlesMapper articlesMapper;

    @Autowired
    private LabelsMapper labelsMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Map<String, Object> login(String telPhone, String password) throws Exception {
        HashMap<String, Object> map = new HashMap();
        if (StringUtils.isEmpty(telPhone) || StringUtils.isEmpty(password)) {
            throw new BusinessException(EnumBusinessError.PARAMETER_INVALID_ERROR, "登录参数不合法");
        }
        password = MyUtil.MD5(password);
        Users loginUser = usersMapper.getUserByTelAndPwd(telPhone, password);
        if (loginUser == null) {
            throw new BusinessException(EnumBusinessError.USER_LOGIN_FAIL);
        }
        if (ADMIN.equals(loginUser.getUserRole())) {
            map.put(ADMIN, ADMIN);
        } else {
            map.put(ADMIN, NOT_ADMIN);
        }
        //生成当前用户专有Token
        UserToken userToken = new UserToken();
        BeanUtils.copyProperties(loginUser, userToken);
        String token = tokenUtils.generateToken(userToken);

        //然后存到redis，并设置时间为1天
        tokenUtils.storageToken(token, telPhone);
        UserToken info = tokenUtils.getInfoFromToken(token);
        map.put(TOKEN, token);
        map.put(LOGIN_USER, info);
        return map;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void register(String password, String telPhone) {
        if (StringUtils.isEmpty(password) || StringUtils.isEmpty(telPhone)) {
            throw new BusinessException(EnumBusinessError.PARAMETER_INVALID_ERROR, "注册参数不合法");
        }

        Users user = usersMapper.getUserByTelPhone(telPhone);
        if (user != null) {
            throw new BusinessException(EnumBusinessError.PHONE_NUMBER_IS_EXIST);
        }
        String userId = FTPUtil.getFileId();
        password = MyUtil.MD5(password);
        String time = myUtil.getCurrentDetailedTime();
        int i = usersMapper.insertUser(userId, password, time, telPhone);
        if (i <= 0) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "注册失败");
        }
        userLevelMapper.insert(userId);
    }

    @Override
    public void telPhoneIsOk(String telPhone) {
        if (StringUtils.isEmpty(telPhone)) {
            throw new BusinessException(EnumBusinessError.PARAMETER_INVALID_ERROR, "手机参数不合法");
        }
        Users user = usersMapper.getUserByTelPhone(telPhone);
        if (user != null) {
            throw new BusinessException(EnumBusinessError.PHONE_NUMBER_IS_EXIST);
        }
    }

    @Override
    public void updateUserInfo(String userName, String userPassword, String userEmail, String userProfilePhoto, String userTelephoneNumber, String userNickname, String userSex, String userIntroduce) throws Exception {
        //第一步先获取当前登录的用户
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        String token = request.getHeader(AUTHORIZATION);
        UserToken loginUser = tokenUtils.getInfoFromToken(token);
        String userId = loginUser.getUserId();
        if (!StringUtils.isEmpty(userPassword)) {
            userPassword = MyUtil.MD5(userPassword);
        }
        int i = usersMapper.updateUserInfo(userId, userName, userPassword, userEmail, userProfilePhoto, userTelephoneNumber, userNickname, userSex, userIntroduce);
        if (i < 0) {
            throw new BusinessException(EnumBusinessError.UNKNOWN_ERROR, "更新用户数据异常，请稍后再试");
        }
    }

    @Override
    public String getUserPassword() {
        //第一步先获取当前登录的用户
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        String token = request.getHeader(AUTHORIZATION);
        UserToken loginUser = tokenUtils.getInfoFromToken(token);
        String userId = loginUser.getUserId();
        String password = usersMapper.getUserPasswordById(userId);
        return password;
    }

    @Override
    public Map<String, Object> getUserInfo(String userId) {
        Map<String, Object> map = new HashMap<>();
        String s = tokenUtils.parseTokenToken();
        UserToken userToken = null;
        Users user = usersMapper.getUserById(userId);
        if (StringUtils.isEmpty(s)) {
            //说明没登录
            map.put(IS_FRIEND, false);
        } else {
            userToken = tokenUtils.getInfoFromToken(s);
            String loginUserId = userToken.getUserId();
            if (userId.equals(loginUserId)) {
                map.put(IS_FRIEND, true);
            } else {
                boolean isFriend = redisTemplate.opsForSet().isMember(loginUserId + _FOCUS, userId);
                if (!isFriend) {
                    map.put(IS_FRIEND, false);
                } else {
                    map.put(IS_FRIEND, true);
                }
            }

        }
        map.put(USERS, user);
        String registrationTime = user.getUserRegistrationTime();
        long currentTimeMillis = System.currentTimeMillis();
        long time = currentTimeMillis - myUtil.parseTimeToString(registrationTime);
        long how = time / 1000 / 60 / 60 / 24 / 30 / 12 + 1;
        map.put(REGISTRATION_TIME, how);
        return map;
    }

    @Override
    public Map<String, Object> getFriendsByFriendIdList(String userId, Integer curPage) {
        Map<String, Object> map = new HashMap<>();
        Set<Object> members = redisTemplate.opsForSet().members(userId + _FOCUS);
        map.put(COUNT, members.size());
        int totalPage = (members.size() + 10 - 1) / 10;
        if (totalPage == 0) {
            map.put(TOTAL_PAGE, 0);
            map.put(FRIENDS, new ArrayList<>());
            return map;
        }
        if (curPage < 1) {
            curPage = 1;
        }
        if (curPage > totalPage) {
            curPage = totalPage;
        }
        map.put(TOTAL_PAGE, totalPage);
        Object[] idsObject = members.toArray();
        ArrayList<String> ids = new ArrayList<>();
        for (int i = 0; i < (idsObject.length < 10 ? idsObject.length : 10); i++) {
            ids.add((String) idsObject[(curPage - 1) * 10 + i]);
        }
        return getStringObjectMap(map, ids, FRIENDS);
    }

    @Override
    public Map<String, Object> getUserMainInfo(String userId) {
        UserMainModel mainModel = new UserMainModel();
        //1、查出用户文章总共被浏览次数
        mainModel.setViewCount(redisUtil.getStringValue(userId, _ARTICLE_VIEWS_COUNT));
        //2、查出用户文章总点赞数
        mainModel.setArticleLikeCount(redisUtil.getStringValue(userId, _UP_COUNT));
        //3、查出用户的标签领域
        List<String> allLabelNameByUserId = labelsMapper.getAllLabelNameByUserId(userId);
        mainModel.setUserId(userId);
        mainModel.setInterests(allLabelNameByUserId);
        //4、 查出用户的粉丝数
        Integer userFansCount = Math.toIntExact(redisTemplate.opsForSet().size(userId + _FANS));
        mainModel.setFansCount(userFansCount);
        //5、文章被收藏数
        mainModel.setCollectsCount(redisUtil.getStringValue(userId, _COLLECT_COUNT));
        //6、查出用户原创文章篇数
        Integer originalCount = articlesMapper.getOriginalArticleCount(userId);
        mainModel.setArticleCount(originalCount);
        //7、查出用户的总评论数
        mainModel.setCommentsCount(redisUtil.getStringValue(userId, _COMMENT_COUNT));
        Map<String, Object> map = new HashMap<>();
        map.put(USER_MAIN_INFO, mainModel);
        return map;
    }

    @Override
    public Map<String, Object> getUserFansByUserId(String userId, Integer curPage) {
        Map<String, Object> map = new HashMap<>();
        Set<Object> members = redisTemplate.opsForSet().members(userId + _FANS);
        map.put(COUNT, members.size());
        int totalPage = (members.size() + 10 - 1) / 10;
        if (totalPage == 0) {
            map.put(TOTAL_PAGE, 0);
            map.put(FANS, new ArrayList<>());
            return map;
        }
        if (curPage < 1) {
            curPage = 1;
        }
        if (curPage > totalPage) {
            curPage = totalPage;
        }
        map.put(TOTAL_PAGE, totalPage);
        Object[] idsObject = members.toArray();
        ArrayList<String> ids = new ArrayList<>();
        for (int i = 0; i < (Math.min(idsObject.length, 10)); i++) {
            ids.add((String) idsObject[(curPage - 1) * 10 + i]);
        }
        return getStringObjectMap(map, ids, FANS);
    }

    private Map<String, Object> getStringObjectMap(Map<String, Object> map, ArrayList<String> ids, String fans2) {
        List<Users> fans = usersMapper.getFriendsByFriendIdList(ids);

        String isLoginToken = tokenUtils.parseTokenToken();
        if (StringUtils.isEmpty(isLoginToken)) {
            //没有登录
            map.put(ALL_NOT_FRIEND, true);
        } else {
            //用户登录了
            if (!tokenUtils.inspectionToken(isLoginToken)) {
                map.put(ALL_NOT_FRIEND, true);//伪造token
            } else {
                UserToken userToken = tokenUtils.getInfoFromToken(isLoginToken);
                fans = fans.stream().peek(friend -> {
                    Boolean isFriend = redisTemplate.opsForSet().isMember(userToken.getUserId() + _FOCUS, friend.getUserId());
                    if (!isFriend) {
                        friend.setUserPassword(FALSE_STRING);
                    } else {
                        friend.setUserPassword(TRUE_STRING);
                    }
                }).collect(Collectors.toList());
            }
        }
        map.put(fans2, fans);
        return map;
    }

    @Override
    public Map<String, Object> isOwnerMainUI(String userId) {
        Map<String, Object> map = new HashMap<>();
        String token = tokenUtils.parseTokenToken();
        if (StringUtils.isEmpty(token)) {
            map.put(IS_OWNER_MAIN_UI, false);
            return map;
        }
        UserToken userToken = tokenUtils.getInfoFromToken(token);
        String tokenUserId = userToken.getUserId();
        if (tokenUserId.equals(userId)) {
            map.put(IS_OWNER_MAIN_UI, true);
        } else {
            map.put(IS_OWNER_MAIN_UI, false);
        }
        return map;
    }

    @Override
    public Map<String, Object> getUserArticleCommentsWithNotPass() {
        Map<String, Object> map = new HashMap<>();
        String token = tokenUtils.parseTokenToken();
        if (StringUtils.isEmpty(token)) {
            map.put(NOT_PASS_COMMENT_COUNT, 0);
            return map;
        }
        UserToken userToken = tokenUtils.getInfoFromToken(token);
        String userId = userToken.getUserId();
        Integer notPassCommentCount = usersMapper.getUserArticleCommentsWithNotPass(userId);
        map.put(NOT_PASS_COMMENT_COUNT, notPassCommentCount);
        return map;
    }
}
